package com.hyunilkim.log4air
{
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.utils.Dictionary;
	
	/**
	 * Simple File Logger class
	 * @author Hyunil Kim (hkim&#64;hyunilkim.com)
	 */
	public final class Logger
	{
		/** @private */
		private static var instances		:Dictionary = new Dictionary();
		/** @private */
		private static var initialized		:Boolean;
		/** @private */
		private var _id						:String;
		/** @private */
		private var file					:File;
		/** @private */
		private var stream					:FileStream;
		/** @private */
		private var time					:Date;
		
		/** @private */
		public function Logger(se:SingletonEnforcer)
		{
			if (se == null)
				throw new Error("Please use getLogger(id:String) method.");
			else
			{
				if (!initialized) initialize();
			}
		}
		
		/**
		 * Used to retreive an instance of Logger. If there's no instance with the given ID, it will be created and returned.
		 * @param id Unique ID of the logger instance
		 * @return an instance of Logger with given ID
		 * 
		 */
		public static function getLogger(id:String):Logger
		{
			var instance:Logger = instances[id];
			if (instance == null)
			{
				instance = new Logger(new SingletonEnforcer());
				instance.id = id;
				instances[id] = instance;
				instance.initialize();
			}
			return (instance as Logger);
		}
		
		/** @private */
		private function initialize():void
		{
			time = new Date();
			
			try
			{
				if (stream != null) stream.close();
				
				var dir:File = new File(File.applicationDirectory.nativePath + "/log");
				if (dir == null || !dir.exists || !dir.isDirectory)
				{
					dir.createDirectory();
				}
				dir = null;
				
				var year:String = String(time.getFullYear());
				
				var month:String = String(time.getMonth());
				if (month.length == 1) month = "0"+month;
				
				var date:String = String(time.getDate());
				
				var hour:String = String(time.getHours());
				var minute:String = String(time.getMinutes());
				var second:String = String(time.getSeconds());
				
				var timeString:String = year+"-"+month+"-"+date;  
				
				file = new File(File.applicationDirectory.nativePath + "/log/"+id+"_"+ timeString +".txt");
				
				stream = new FileStream();
				stream.open(file, FileMode.APPEND);
				
				initialized = true;
			}
			catch (e:Error)
			{
				trace(e.getStackTrace());
			}
		}
		
		/** @private */
		private function checkTime():void
		{
			if (time != null)
			{
				var now:Date = new Date();
				if (now.getDate() > time.getDate())
				{
					initialize();
				}
			}
		}
		
		/**
		 * info will write a new line starting with "-- [INFO] " to the FileStream open
		 * @param message	message to output
		 */
		public function info(message:String):void
		{
			checkTime();
			if (stream != null && initialized) stream.writeUTFBytes("-- [INFO] "+time.toString()+" : "+message+"\r");
		}
		
		/**
		 * system will write a new line starting with "-- [SYSTEM] " to the FileStream open
		 * @param message	message to output
		 */
		public function system(message:String):void
		{
			checkTime();
			if (stream != null && initialized) stream.writeUTFBytes("-- [SYSTEM] "+time.toString()+" : "+message+"\r");
		}
		
		/**
		 * debug will write a new line starting with "-- [DEBUG] " to the FileStream open
		 * @param message	message to output
		 */
		public function debug(message:String):void
		{
			checkTime();
			if (stream != null && initialized) stream.writeUTFBytes("-- [DEBUG] "+time.toString()+" : "+message+"\r");
		}
		
		/**
		 * error will write a new line starting with "-- [ERROR] " to the FileStream open
		 * @param message	message to output
		 */
		public function error(message:String):void
		{
			checkTime();
			if (stream != null && initialized) stream.writeUTFBytes("-- [ERROR] "+time.toString()+" : "+message+"\r");
		}
		
		public function set id(_id:String):void
		{
			this._id = _id;
		}
		
		public function get id():String
		{
			return _id;
		}
		
	}
}

class SingletonEnforcer
{
	public function SingletonEnforcer();
}